package com.tsm.picachu.gameplay.ui;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.R.color;
import android.app.Dialog;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;

import com.tsm.picachu.GeneralActivity;
import com.tsm.picachu.R;
import com.tsm.picachu.common.Constant;
import com.tsm.picachu.common.DialogMenuLose;
import com.tsm.picachu.common.DialogMenuPause;
import com.tsm.picachu.common.Utils;
import com.tsm.picachu.data.User;
import com.tsm.picachu.gameplay.data.Cell;
import com.tsm.picachu.gameplay.data.Game;
import com.tsm.picachu.gameplay.data.Value;
import com.tsm.picachu.level.ui.SelectLevelActivity;
import com.tsm.picachu.level.ui.UnlockLevelActivity;

public class GamePlayActivity extends GeneralActivity
{
	private static final int[] CELL_IDS = { R.drawable.item_1,
			R.drawable.item_2, R.drawable.item_3, R.drawable.item_4,
			R.drawable.item_5, R.drawable.item_6, R.drawable.item_7,
			R.drawable.item_8, R.drawable.item_9, R.drawable.item_10,
			R.drawable.item_11, R.drawable.item_12, R.drawable.item_13,
			R.drawable.item_14, R.drawable.item_15, R.drawable.item_16,
			R.drawable.item_17, R.drawable.item_18, R.drawable.item_19,
			R.drawable.item_20, R.drawable.item_21, R.drawable.item_22,
			R.drawable.item_23, R.drawable.item_24, R.drawable.item_25,
			R.drawable.item_26 };

	private static final int CELL_GAP_WIDTH = 1;
	private static final int CELL_GAP_HEIGHT = 1;

	/** Dialogs */
	private static final int DIALOG_PAUSE = 0;
	private static final int DIALOG_LOSE = 1;

	/** Image cell sizes */
	private int CELL_IMAGE_WIDTH;
	private int CELL_IMAGE_HEIGHT;

	/** List of cells in the shortest path of two cells */
	// private List<Cell> mCellOfLines;

	/** For top bar */
	private LinearLayout mLayoutTop = null;

	/** For center squares */
	private LinearLayout mLayoutTable = null;

	/** For animations */
	private LinearLayout mLayoutOverAnim = null;

	/** For chosen point */
	private LinearLayout mChosenCell = null;

	/** For core */
	private TextView mTextCore = null;

	/** For time */
	private View mTimeBar = null;
	private Timer mTimer = null;
	private int TIME_BAR_WIDTH;
	private static final int TIME_BAR_PERCENT_WIDTH = 55;

	private Button mButtonPause = null;

	/** Level in game */
	private TextView mTextLevel = null;
	private ImageView mImageEndLevel = null;

	/** User info */
	private User mUser = null;

	/** Game info */
	private Game mGame = null;

	/** Animation Fireworks on match two cells */
	private boolean mIsChoosed = false;

	/** Humans in game */
	private TextView mTextHumans = null;

	/** Check runnable steps */
	private Timer mTimerCheckRunnable = null;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);

		setContentView(R.layout.page_gameplay);

		mLayoutTable = (LinearLayout) findViewById(R.id.layout_center);
		mLayoutTop = (LinearLayout) findViewById(R.id.layout_top);
		mLayoutOverAnim = (LinearLayout) findViewById(R.id.layout_center_anim);
		mTimeBar = findViewById(R.id.time_bar);

		initGameSize();
		initGamePlay();
		initUser();

		initInterface();

		mButtonPause.setOnClickListener(new OnClickListener()
		{
			public void onClick(View v)
			{
				stopTime();
				showDialog(DIALOG_PAUSE);
			}
		});
	}

	private void initGameSize()
	{
		BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(
				CELL_IDS[0]);
		Bitmap bitmap = bitmapDrawable.getBitmap();
		CELL_IMAGE_HEIGHT = bitmap.getHeight();
		CELL_IMAGE_WIDTH = bitmap.getWidth();

		DisplayMetrics displayMetrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

		Rect rectOfTop = new Rect();
		mLayoutTop.getHitRect(rectOfTop);

		int totalRows = (displayMetrics.heightPixels - rectOfTop.height() - Utils.getNotifictionBarHeight(this))
				/ (CELL_IMAGE_HEIGHT + CELL_GAP_HEIGHT * 2);

		// Get total columns is a even number
		int totalCols = displayMetrics.widthPixels
				/ (CELL_IMAGE_WIDTH + CELL_GAP_WIDTH * 2);
		if (totalCols % 2 != 0)
		{
			totalCols--;
		}

		mGame = new Game(totalRows, totalCols);
	}

	private void initUser()
	{
		String username = getIntent().getStringExtra(Constant.EXTRA_USERNAME);
		mUser = Utils.getUserData(this, username);
	}

	private void initInterface()
	{
		mImageEndLevel = (ImageView) findViewById(R.id.image_anim_end_level);

		mTextCore = (TextView) findViewById(R.id.text_core);

		mButtonPause = (Button) findViewById(R.id.button_pause);
		mTextLevel = (TextView) findViewById(R.id.text_level);
		mTextHumans = (TextView) findViewById(R.id.text_human);

		String levelStr = getIntent().getStringExtra(
				Constant.EXTRA_CURRENT_LEVEL);
		String miniLevelStr = getIntent().getStringExtra(
				Constant.EXTRA_CURRENT_MINI_LEVEL);

		mGame.setLevel(TextUtils.isEmpty(levelStr) ? 1 : Integer.parseInt(levelStr));
		mGame.setMiniLevel(TextUtils.isEmpty(miniLevelStr) ? 1 : Integer.parseInt(miniLevelStr));

		mTextLevel.setText(getString(R.string.level) + " " + mGame.getLevel()
				+ " - " + mGame.getMiniLevel());

		mTextHumans.setText("" + mUser.getHuman());
		mTextCore.setText("" + mGame.getCore());
	}

	@Override
	protected Dialog onCreateDialog(int id)
	{
		if (id == DIALOG_PAUSE)
		{
			final DialogMenuPause dialogMenuPause = new DialogMenuPause(this);
			OnClickListener resumeClickListener = new OnClickListener()
			{
				public void onClick(View v)
				{
					dialogMenuPause.hide();
					startTime();
				}
			};
			OnClickListener quitClickListener = new OnClickListener()
			{
				public void onClick(View v)
				{
					setResult(RESULT_CANCELED);
					finish();
				}
			};
			dialogMenuPause.setClickListeners(resumeClickListener,
					quitClickListener);
			return dialogMenuPause;
		}
		else if (id == DIALOG_LOSE)
		{
			final DialogMenuLose dialogMenuLose = new DialogMenuLose(this);
			OnClickListener restartClickListener = new OnClickListener()
			{
				public void onClick(View v)
				{
					dialogMenuLose.hide();
					initGamePlay();
				}
			};

			OnClickListener chooseLevelClickListener = new OnClickListener()
			{
				public void onClick(View v)
				{
					dialogMenuLose.hide();

					startActivity(SelectLevelActivity.class);
				}
			};
			dialogMenuLose.setClickListeners(restartClickListener,
					chooseLevelClickListener);
			return dialogMenuLose;
		}

		return super.onCreateDialog(id);
	}

	private void fillTableValue(List<Integer> idFillList)
	{
		for (int indexRow = 0; indexRow < mGame.getTotalRow(); indexRow++)
		{
			for (int indexColumn = 0; indexColumn < mGame.getTotalColumn(); indexColumn++)
			{
				if (mGame.getValueAt(indexRow, indexColumn) == Value.VALUE_TEMP)
				{
					int numberInFillList = Utils.getNumberRandom(idFillList.size());
					mGame.setValueAt(indexRow, indexColumn,
							idFillList.get(numberInFillList));
					mGame.addRemainCell(new Cell(indexRow, indexColumn));
					idFillList.remove(numberInFillList);
				}
			}
		}

		startCheckRunnable();
	}

	private List<Integer> getALlIdWillBeFill(int totalId)
	{
		List<Integer> idFillList = new ArrayList<Integer>();
		final int MAX_ID = getTotalId();
		int countIdOrigin = 0;
		int countIdFill = 0;
		while (countIdFill < totalId)
		{
			idFillList.add(CELL_IDS[countIdOrigin]);
			idFillList.add(CELL_IDS[countIdOrigin]);

			countIdFill += 2;

			countIdOrigin++;
			if (countIdOrigin == MAX_ID)
			{
				countIdOrigin = 0;
			}
		}

		return idFillList;
	}

	private int getTotalId()
	{
		int idMiniLevel = mGame.getMiniLevel() <= (Constant.TOTAL_MINI_LEVELS >> 1) ? 0 : 1;
		return CELL_IDS.length - Constant.TOTAL_LEVELS * 2 + mGame.getLevel() + idMiniLevel;
	}

	private int initCellIds()
	{
		int totalRealValues = 0;

		for (int indexRow = 0; indexRow < mGame.getTotalRow(); indexRow++)
		{
			int totalColumnsReal = /* getTotalColumnsARowRandom */(mGame.getTotalColumn());
			totalRealValues += totalColumnsReal;
			int indexColumnStart = (mGame.getTotalColumn() - totalColumnsReal) / 2;

			for (int indexColumn = 0; indexColumn < mGame.getTotalColumn(); indexColumn++)
			{
				if (indexColumn >= indexColumnStart
						&& indexColumn < indexColumnStart + totalColumnsReal)
				{
					mGame.setValueAt(indexRow, indexColumn, Value.VALUE_TEMP);
				}
				else
				{
					mGame.setValueAt(indexRow, indexColumn, Value.VALUE_NONE);
				}
			}
		}

		return totalRealValues;
	}

	/** Get total columns of a row belongs to [2, totalColumns]. It is even */
	@SuppressWarnings("unused")
	private int getTotalColumnsARowRandom(int totalColumns)
	{
		int number = Utils.getNumberRandom(totalColumns - 1) + 2;

		if (number % 2 != 0)
		{
			number--;
		}
		return number;
	}

	private void fillTableView()
	{
		for (int indexRow = 0; indexRow < mGame.getTotalRow(); indexRow++)
		{
			final LinearLayout layoutRow = new LinearLayout(this);
			layoutRow.setGravity(Gravity.CENTER);
			layoutRow.setLayoutParams(new LayoutParams(
					LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

			final LinearLayout layoutRowAnim = new LinearLayout(this);
			layoutRowAnim.setGravity(Gravity.CENTER);
			layoutRowAnim.setLayoutParams(new LayoutParams(
					LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

			for (int indexColumn = 0; indexColumn < mGame.getTotalColumn(); indexColumn++)
			{
				final LinearLayout cellView = new LinearLayout(this);
				final Button buttonInCell = new Button(this);

				LinearLayout.LayoutParams layoutParamsCell = new LinearLayout.LayoutParams(
						CELL_IMAGE_WIDTH, CELL_IMAGE_HEIGHT);
				layoutParamsCell.bottomMargin = CELL_GAP_HEIGHT;
				layoutParamsCell.topMargin = CELL_GAP_HEIGHT;
				layoutParamsCell.leftMargin = CELL_GAP_WIDTH;
				layoutParamsCell.rightMargin = CELL_GAP_WIDTH;

				if (!mGame.isCellEmpty(indexRow, indexColumn))
				{
					buttonInCell.setBackgroundResource(mGame.getValueAt(
							indexRow, indexColumn));
				}

				buttonInCell.setTag(new Cell(indexRow, indexColumn));

				buttonInCell.setOnClickListener(new OnClickListener()
				{
					public void onClick(View view)
					{
						if (mIsChoosed)
							return;

						if (mChosenCell == null)
						{
							mChosenCell = cellView;
							mChosenCell.setBackgroundResource(R.drawable.bg_cell_chosen);
						}
						else
						{
							final Cell currentCell = (Cell) buttonInCell.getTag();
							final Cell lastCell = (Cell) ((Button) mChosenCell.getChildAt(0)).getTag();

							if (lastCell.getRow() != currentCell.getRow()
									|| lastCell.getCol() != currentCell.getCol())
							{
								if (mGame.isRightMove(lastCell, currentCell))
								{
									mGame.removeCell(lastCell);
									mGame.removeCell(currentCell);
									
									if (mGame.isSameRunnable(currentCell,
											lastCell) && mGame.getNumberOfRemainCells() != 0)
									{
										mGame.clearRunnable();
										startCheckRunnable();
									}

									mIsChoosed = true;

									cellView.setBackgroundResource(R.drawable.bg_cell_chosen);

									final ImageView imageViewChosenCell = (ImageView) ((ViewGroup) (mLayoutOverAnim.getChildAt(lastCell.getRow()))).getChildAt(lastCell.getCol());
									final ImageView imageViewCell = (ImageView) ((ViewGroup) (mLayoutOverAnim.getChildAt(currentCell.getRow()))).getChildAt(currentCell.getCol());

									final int timePeriodLayer = Constant.TIME_ANIM_FIREWORKS
											/ Constant.FIREWORKS_NUMBER_LAYERS;

									TimerTask timerTask = new TimerTask()
									{
										private int numberLayerProcess = 0;

										@Override
										public void run()
										{
											numberLayerProcess++;
											runOnUiThread(new Runnable()
											{
												public void run()
												{
													imageViewChosenCell.setImageResource(R.drawable.fireworks_1
															+ numberLayerProcess);
													imageViewCell.setImageResource(R.drawable.fireworks_1
															+ numberLayerProcess);

													if (numberLayerProcess >= Constant.FIREWORKS_NUMBER_LAYERS)
													{
														processRightMove(
																cellView,
																currentCell,
																lastCell,
																imageViewChosenCell,
																imageViewCell);

														mIsChoosed = false;
														mChosenCell.setVisibility(View.INVISIBLE);
														mChosenCell = null;

														cancel();
													}
												}
											});
										}
									};
									Timer timer = new Timer();
									timer.schedule(timerTask, 0,
											timePeriodLayer);
								}
								else
								{
									mChosenCell.setBackgroundDrawable(new ColorDrawable(
											color.transparent));
									mChosenCell = null;
								}
							}
						}
					}
				});

				cellView.addView(buttonInCell, layoutParamsCell);
				layoutRow.addView(cellView);

				final ImageView imageView = new ImageView(this);
				layoutRowAnim.addView(imageView, layoutParamsCell);
			}

			mLayoutTable.addView(layoutRow);
			mLayoutOverAnim.addView(layoutRowAnim);
		}
	}

	private void refreshTableView()
	{
		for (int indexRow = 0; indexRow < mLayoutTable.getChildCount(); indexRow++)
		{
			final LinearLayout layoutRow = (LinearLayout) mLayoutTable.getChildAt(indexRow);

			for (int indexColumn = 0; indexColumn < layoutRow.getChildCount(); indexColumn++)
			{
				final LinearLayout cellView = (LinearLayout) layoutRow.getChildAt(indexColumn);
				cellView.setBackgroundColor(Color.TRANSPARENT);
				final Button buttonInCell = (Button) cellView.getChildAt(0);

				if (!mGame.isCellEmpty(indexRow, indexColumn))
				{
					buttonInCell.setBackgroundResource(mGame.getValueAt(
							indexRow, indexColumn));
				}
				else
				{
					buttonInCell.setBackgroundColor(Color.TRANSPARENT);
				}

				cellView.setVisibility(View.VISIBLE);
			}
		}
	}

	private void processCore(int dCore)
	{
		mGame.setCore(mGame.getCore() + dCore);
		mTextCore.setText("" + mGame.getCore());
	}

	private void processWin()
	{
		stopTime();

		mGame.setMiniLevel(mGame.getMiniLevel() + 1);

		processWinMiniLevel();
	}

	private void processWinMiniLevel()
	{
		saveUserHuman(mUser.getHuman() + Constant.TOTAL_HUMANS_A_MINI_LEVEL);

		final int timePeriodLayer = Constant.TIME_ANIM_END_LEVEL
				/ Constant.END_LEVEL_NUMBER_LAYERS;

		TimerTask timerTask = new TimerTask()
		{
			private int numberLayerProcess = 0;

			@Override
			public void run()
			{
				runOnUiThread(new Runnable()
				{
					public void run()
					{
						mImageEndLevel.setImageResource(R.drawable.end_mini_level_1
								+ numberLayerProcess);

						if (numberLayerProcess >= Constant.END_LEVEL_NUMBER_LAYERS)
						{
							mImageEndLevel.setImageDrawable(new ColorDrawable(
									Color.TRANSPARENT));

							int miniLevel = mGame.getMiniLevel();

							if (miniLevel > Constant.TOTAL_MINI_LEVELS)
							{
								processWinLevel();
							}
							else
							{
								if (miniLevel > mUser.getMiniLevel())
								{
									mUser.setMiniLevel(miniLevel);
									Utils.savePreference(GamePlayActivity.this,
											mUser.getName(),
											Constant.PREFERENCE_KEY_MINI_LEVEL,
											miniLevel + "");
								}

								mTextLevel.setText(getString(R.string.level)
										+ " " + mGame.getLevel() + " - "
										+ mGame.getMiniLevel());

								initGamePlay();
							}
							cancel();
						}
					}
				});

				numberLayerProcess++;
			}
		};
		Timer timer = new Timer();
		timer.schedule(timerTask, 0, timePeriodLayer);
	}

	private void processWinLevel()
	{
		saveUserHuman(mUser.getHuman() + Constant.TOTAL_HUMANS_A_LEVEL);

		int level = mGame.getLevel();
		mGame.setLevel(++level);

		if (level > Constant.TOTAL_LEVELS || level <= mUser.getLevel())
		{
			startActivity(SelectLevelActivity.class);
		}
		else
		{
			mUser.setLevel(level);
			Utils.savePreference(this, mUser.getName(),
					Constant.PREFERENCE_KEY_LEVEL, level + "");

			startActivity(UnlockLevelActivity.class);
		}
	}

	private void initGamePlay()
	{
		TIME_BAR_WIDTH = com.util.library.common.Utils.getScreenWidth(this)
				* TIME_BAR_PERCENT_WIDTH / 100;

		mGame.setTotalTime(Constant.TIME_MAX_PLAYING);
		mGame.setTime(mGame.getTotalTime());

		mTimeBar.getLayoutParams().width = 0;

		startTime();

		int totalRealValues = initCellIds();
		List<Integer> idFillList = getALlIdWillBeFill(totalRealValues);
		fillTableValue(idFillList);

		if (mLayoutTable.getChildCount() != 0)
		{
			refreshTableView();
		}
		else
		{
			fillTableView();
		}
	}

	private void stopTime()
	{
		if (mTimer != null)
		{
			mTimer.cancel();
			mTimer = null;
		}

		stopCheckRunnable();
	}

	private void startTime()
	{
		final TimerTask timerTask = new TimerTask()
		{
			@Override
			public void run()
			{
				runOnUiThread(new Runnable()
				{
					public void run()
					{
						mGame.setTime(mGame.getTime() - 1);

						mTimeBar.getLayoutParams().width = (int) (TIME_BAR_WIDTH
								* (mGame.getTotalTime() - mGame.getTime())
								/ mGame.getTotalTime() * 1.f);
						mTimeBar.requestLayout();

						if (mGame.getTime() <= 0)
						{
							showDialog(DIALOG_LOSE);
							cancel();
						}
					}
				});
			}
		};

		mTimer = new Timer();
		mTimer.schedule(timerTask, 0, 1000);
	}

	@Override
	public void onBackPressed()
	{
		stopTime();
		showDialog(DIALOG_PAUSE);
	}

	private void processRightMove(final LinearLayout cellView,
			final Cell currentCell, final Cell lastCell,
			final ImageView imageViewChosenCell, final ImageView imageViewCell)
	{
		imageViewChosenCell.setImageDrawable(new ColorDrawable(
				Color.TRANSPARENT));
		imageViewCell.setImageDrawable(new ColorDrawable(Color.TRANSPARENT));

		cellView.setVisibility(View.INVISIBLE);

		processCore(Constant.CORE_ONE_MATCHED_ITEM);

		if (mGame.getNumberOfRemainCells() == 0)
		{
			processCore(Constant.CORE_ONE_LEVEL);
			processWin();
		}
	}

	private void saveUserHuman(int human)
	{
		mUser.setHuman(human);
		Utils.savePreference(GamePlayActivity.this, mUser.getName(),
				Constant.PREFERENCE_KEY_HUMAN, mUser.getHuman() + "");
	}

	private void startCheckRunnable()
	{
		TimerTask timerTask = new TimerTask()
		{
			@Override
			public void run()
			{
				com.util.library.common.Utils.debug("startCheckRunnable");
				mGame.findRunnableCells();

				boolean hasChanged = false;
				while (!mGame.isRunnable())
				{
					mGame.makeRunnable();
					hasChanged = true;
					mGame.findRunnableCells();
				}

				if (!hasChanged)
				{
					return;
				}

				runOnUiThread(new Runnable()
				{
					public void run()
					{
						int human = mUser.getHuman() - 1;
						if (human == 0)
						{
							showDialog(DIALOG_LOSE);
							saveUserHuman(Constant.TOTAL_HUMANS_FIRST);
							cancel();
							return;
						}

						saveUserHuman(human);

						mTextHumans.setText("" + mUser.getHuman());
						refreshTableView();
					}
				});
			}
		};

		mTimerCheckRunnable = new Timer();
		mTimerCheckRunnable.schedule(timerTask, 0);
	}

	private void stopCheckRunnable()
	{
		if (mTimerCheckRunnable != null)
		{
			mTimerCheckRunnable.cancel();
			mTimerCheckRunnable = null;
		}
	}
}
